package com.game.service.socket;


import com.game.service.app.*;
import com.game.service.app.get_score.*;
import com.game.service.app.match.GetMatchEvent;
import com.game.service.app.match.MatchEvent;
import com.game.service.app.match.OnlineUser;
import com.game.service.app.turntable.*;
import com.game.service.beans.GameMessage;
import com.game.service.beans.Login;
import com.game.service.beans.UserInfo;
import com.game.service.comm.AESUtils;
import com.game.service.comm.AdvancedCommandDuplicateChecker;
import com.game.service.comm.EncipheredData;
import com.game.service.db.UserScoreDaoImpl;
import com.game.service.game.redblack.RedBlackConfig;
import com.game.service.game.redblack.RedBlackMatch;
import com.game.service.game.redblack.RedBlackTable;
import com.game.service.game.turntable.*;
import com.game.service.game.turntable.config.*;
import com.game.service.game.turntable.control.PrintGameRunInfo;
import com.game.service.game.turntable.email.EmailDeal;
import com.game.service.game.turntable.email.UserEmail;
import com.game.service.windows.Client;
import com.game.service.windows.LogWindows;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.java_websocket.WebSocket;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.lang.reflect.Type;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.game.service.app.Score.*;
import static com.game.service.app.Utils.LogDate;
import static com.game.service.define.GameDefine.*;
import static com.game.service.define.RoomConfig.*;


public class SocketServer extends WebSocketServer {

    static SocketServer mKernel;
    private long tableIdIndex = 100000000;//游戏场次ID

    private final ConcurrentHashMap<Integer, UserInfo> userMap = new ConcurrentHashMap<>();

    public ConcurrentHashMap<Integer, UserInfo> getUserMap() {
        return userMap;
    }

    private final ConcurrentHashMap<Integer, WebSocket> webMap = new ConcurrentHashMap<>();

    public static SocketServer getKernel() {
        if (mKernel == null) {
            mKernel = new SocketServer(PORT);
            mKernel.start();
        }
        return mKernel;
    }

    ExecutorService executor;
    AdvancedCommandDuplicateChecker checker = new AdvancedCommandDuplicateChecker();

    private SocketServer(int port) {
        super(new InetSocketAddress(port));
        mKernel = this;
        //  initConfig();
        RedBlackMatch.getInstance();//加载比赛程序
        FileUtils.writeTxtToFile("游戏重启,服务器正常运行\n", LogDate(), LOG_NAME_ROOM);
        executor = Executors.newSingleThreadExecutor();
        onGameRun();
    }


    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {

        String ip = conn.getRemoteSocketAddress().getAddress().getHostAddress();
        int port = conn.getRemoteSocketAddress().getPort();
        int size = this.getConnections().size();
        String log = "【" + ip + ":" + port + "】—>Entered the room! 连接数量=" + size;
        LogWindows.getLogWindows().printToTextArea(log, SocketServer.class);

//        if (checker.isDuplicate(""+login.getUid(),"")) {
//            //如果重复发生则不处理这条指令
//            LogWindows.getLogWindows().printToTextArea(login.getUid()+"重复登录", SocketServer.class);
//            return;
//        }
        send(conn, GAME_MAIN, GAME_SUB_SOCKET_SUCCESS, null);
    }


    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        //  broadcast(conn + " has left the room!");
        String ip = conn.getRemoteSocketAddress().getAddress().getHostAddress();
        int port = conn.getRemoteSocketAddress().getPort();
        String log = "【" + ip + ":" + port + "】 >> Exit the room!" + code + reason;
        webMap.forEach((key, value) -> {
            if (conn == value) {
                userMap.remove(key);
                LogWindows.getLogWindows().printToTextArea(log, SocketServer.class);
            }
        });

    }


    @Override
    public void onMessage(WebSocket conn, String message) {

        try {
            Gson gson = new Gson();
            GameMessage gameMessage = gson.fromJson(message, GameMessage.class);
            final int main = gameMessage.getMain();
            final int sub = gameMessage.getSub();

            switch (main) {
                case GAME_MAIN:
                    //猜大小游戏消息
                    onSub(conn, sub, message);
                    break;
                case 201:
                    //其他游戏预留
                    break;
                case 0:
                    if (sub == 0) {
                        send(conn, 0, 0, null);
                    }
                    break;
                default:
                    break;
            }

        } catch (Exception e) {
            String error = "onMessage()" + e + "\n" + Arrays.toString(e.getStackTrace());
            FileUtils.writeTxtToFile(error, LogDate(), LOG_NAME_ERROR);
        }


    }


    @Override
    public void onError(WebSocket conn, Exception e) {
        System.out.println("onError()" + e);
        String error = "onError()" + e + "\n" + Arrays.toString(e.getStackTrace());
        FileUtils.writeTxtToFile(error, LogDate(), "err.txt");


    }

    @Override
    public void onStart() {
        LogWindows.getLogWindows().printToTextArea("Server started!", SocketServer.class);
        setConnectionLostTimeout(0);
        setConnectionLostTimeout(100);
    }


    private void onSub(WebSocket conn, int sub, String json) {
        if (Client.isClose()) {
            //不能继续游戏了。
            return;
        }
        switch (sub) {
            case GAME_C_SUB_ENTER_ROOM:
                EnterRoom(conn, json);
                break;
            case GAME_C_SUB_BET:
                Bet(conn, json);
                break;
            case GAME_C_SUB_EXCHANGE_PRIZE_DAILY:
                exchangePrizeDaily(conn, json);
                break;
            case GAME_C_SUB_EXCHANGE_PRIZE_LUCKY_VALUE:
                exchangePrizeLuckyValue(conn, json);
                break;
            case GAME_C_SUB_EMAIL_LIST:
                getEmailList(conn, json);
                break;
            case GAME_C_SUB_EMAIL_CLAIM_PRIZE:
                emailClaimPrize(conn, json);
                break;
            case GAME_C_SUB_EMAIL_DELETE:
                emailDelete(conn, json);
                break;
            case GAME_C_SUB_MATCH_RANKING:
                RedBlackMatch.getInstance().getMatchRanking(conn);
                break;

            default:
                break;
        }
    }

    /***兑换幸运积分
     *
     * @param conn WebSocket
     * @param json 用户发送信息
     */
    private void exchangePrizeLuckyValue(WebSocket conn, String json) {
        Type type = new TypeToken<GameMessage<UserExchangePrizeLuckyValue>>() {
        }.getType();//无敌好用
        GameMessage<UserExchangePrizeLuckyValue> data = new Gson().fromJson(json, type);
        UserExchangePrizeLuckyValue user = data.getCmd();
        if (user == null) {
            return;
        }
        UserInfo userInfo = getUser(user.getUid(), user.getToken());
        if (userInfo == null) {//校验玩家token,信息错误则忽略请求
            return;
        }

        user.setOrderIdPrize(orderIdHead() + ORDER_EXCHANGE_LUCKY_VALUE + tableIdIndex);
        PrizeLucky prizeLucky = userInfo.getPrize().exchangeLuckyValue(user.getPrizeLuckyValueCode());
        send(conn, GAME_MAIN, GAME_C_SUB_EXCHANGE_PRIZE_LUCKY_VALUE_RETURN, prizeLucky);
        send(conn, GAME_MAIN, GAME_SUB_GAME_PRIZE_LIST, userInfo.getPrize());//同步发送玩家的个人游戏信息
        if (prizeLucky != null) {
            executor.submit(() -> {
                long start = System.currentTimeMillis();
                if (userInfo.getPrize() != null) {
                    userInfo.getPrize().write();//写入数据库
                }
                String postJson = createExchangePrizeLuckyValueJson(user, prizeLucky);
                //游戏结算订单-幸运积分直接结算
                PostJsonDeal postJsonDeal = new PostJsonDeal();
                postJsonDeal.post(postJson, API_POST_PRIZE_ORDER, PostJsonDeal.POST_TYPE_EXCHANGE_PRIZE_LUCKY_VALUE, user.getOrderIdPrize(), user.getUid());
                //游戏结算订单-邮件系统-记录此次操作
                EmailDeal emailDeal = new EmailDeal();
                emailDeal.record(postJson, API_POST_PRIZE_ORDER, EmailDeal.EMAIL_TYPE_EXCHANGE, user.getOrderIdPrize(), user.getUid());

                FileUtils.writeTxtToFile(writeLog(postJson, PostJsonDeal.POST_TYPE_EXCHANGE_PRIZE_LUCKY_VALUE), LogDate(), getFileName(user.getUid()));
                printTime(user.getOrderIdPrize() + "兑换积分-订单写入", start);

            });
        }


    }

    /***领取每日奖品
     *
     * @param conn WebSocket
     * @param json 用户发送信息
     */
    private void exchangePrizeDaily(WebSocket conn, String json) {
        Type type = new TypeToken<GameMessage<UserExchangePrizeDaily>>() {
        }.getType();//无敌好用
        GameMessage<UserExchangePrizeDaily> data = new Gson().fromJson(json, type);
        UserExchangePrizeDaily userExchangePrizeDaily = data.getCmd();
        if (userExchangePrizeDaily == null) {
            return;
        }
        UserInfo userInfo = getUser(userExchangePrizeDaily.getUid(), userExchangePrizeDaily.getToken());
        if (userInfo == null) {//校验玩家token,信息错误则忽略请求
            return;
        }

        final int betIndex = userExchangePrizeDaily.getBetIndex();
        final int prizeDailyIndex = userExchangePrizeDaily.getPrizeDailyIndex();

        exchangePrizeDaily(conn, userInfo, betIndex, prizeDailyIndex, userExchangePrizeDaily);


    }

    private void exchangePrizeDaily(WebSocket conn, UserInfo userInfo, int betIndex, int prizeDailyIndex, UserExchangePrizeDaily userExchangePrizeDaily) {
        //区分一键领取,单个领取
        ArrayList<PrizeDaily> prizeDailyList;
        if (prizeDailyIndex == -1) {//一键领取全部
            prizeDailyList = userInfo.getPrize().exchangePrizeDailyAll();
        } else {//单个领取
            prizeDailyList = userInfo.getPrize().exchangePrizeDaily(betIndex, prizeDailyIndex);
        }
        send(conn, GAME_MAIN, GAME_C_SUB_EXCHANGE_PRIZE_DAILY_RETURN, prizeDailyList);
        send(conn, GAME_MAIN, GAME_SUB_GAME_PRIZE_LIST, userInfo.getPrize());//同步发送用户信息
        //逐条写入数据库，以及发送到总服务器
        for (PrizeDaily prizeDaily : prizeDailyList) {
            //通过转换成json，再重新转成新的对象
            Gson gson = new Gson();
            String mm = gson.toJson(userExchangePrizeDaily);
            UserExchangePrizeDaily mUserExchangePrizeDaily = gson.fromJson(mm, UserExchangePrizeDaily.class);
            String orderIdPrize = orderIdHead() + ORDER_EXCHANGE_DAILY_TASK + tableIdIndex;//TODO
            mUserExchangePrizeDaily.setOrderIdPrize(orderIdPrize);
            executor.submit(() -> {
                long start = System.currentTimeMillis();
                if (userInfo.getPrize() != null) {
                    userInfo.getPrize().write();//写入数据库
                }
                PostJsonDeal postJsonDeal = new PostJsonDeal();
                //TODO 游戏结算订单-任务奖励
                String postJson = createExchangePrizeDailyJson(mUserExchangePrizeDaily, prizeDaily);
                postJsonDeal.post(postJson, API_POST_PRIZE_ORDER, PostJsonDeal.POST_TYPE_EXCHANGE_PRIZE_DAILY, mUserExchangePrizeDaily.getOrderIdPrize(), userExchangePrizeDaily.getUid());

                //游戏结算订单-邮件系统-记录此次操作
                EmailDeal emailDeal = new EmailDeal();
                emailDeal.record(postJson, API_POST_PRIZE_ORDER, EmailDeal.EMAIL_TYPE_DAILY_TASK, mUserExchangePrizeDaily.getOrderIdPrize(), mUserExchangePrizeDaily.getUid());

                FileUtils.writeTxtToFile(writeLog(postJson, PostJsonDeal.POST_TYPE_EXCHANGE_PRIZE_DAILY), LogDate(), getFileName(mUserExchangePrizeDaily.getUid()));
                printTime(mUserExchangePrizeDaily.getOrderIdPrize() + "每日活动订单写入", start);
            });
        }

    }


    private void EnterRoom(WebSocket conn, String json) {
        Gson gson = new Gson();
        //玩家进入房间
        Type type = new TypeToken<GameMessage<Login>>() {
        }.getType();//无敌好用
        GameMessage<Login> data = gson.fromJson(json, type);
        Login login = data.getCmd();
        if (Client.isClose()) {//点击关闭后,禁止玩家登录
            return;
        }
        if (checker.isDuplicate("" + login.getUid(), "")) {
            //如果重复发生则不处理这条指令
            LogWindows.getLogWindows().printToTextArea(login.getUid() + "重复登录", SocketServer.class);
            return;
        }

        new Thread(() -> {

            //   String json0 = gson.toJson(login);
            //加密数据发送
            String plainText = new Gson().toJson(login);
            EncipheredData eventJson = AESUtils.createEncipheredData(plainText);
            String json0 = new Gson().toJson(eventJson);
            String log = (FileUtils.getTime() + data + ",请求地址" + API_GET_COIN + "数据" + json0);
            LogWindows.getLogWindows().printToTextArea(log, SocketServer.class);
            final String result = doPostForm(API_GET_COIN, json0);
            LogWindows.getLogWindows().printToTextArea("返回-" + result, SocketServer.class);
            //获取失败为空，错误信息
            if (result.isEmpty()) {
                FileUtils.writeTxtToFile("进入房间,获取账户分数失败" + login, LogDate(), getFileName(login.getUid()));
                JsonBean<String> cmd = new JsonBean<>();
                cmd.code = GAME_C_USER_GET_MONEY_ERROR;
                cmd.msg = "Failed to obtain score";
                sendErrorMsg(conn, cmd);
                return;
            }

            Type json_bean_type = new TypeToken<JsonBean>() {
            }.getType();
            JsonBean json_bean = gson.fromJson(result, json_bean_type);
            if (json_bean.code != 0) {
                FileUtils.writeTxtToFile("进入房间,获取账户分数失败" + login + json_bean, LogDate(), getFileName(login.getUid()));
                JsonBean cmd = new JsonBean();
                cmd.code = json_bean.code;
                cmd.msg = "Failed to obtain score,code=" + json_bean.code;
                sendErrorMsg(conn, cmd);
            } else {
                //优先发送该游戏的配置信息
                // sendGameConfig(conn);
                //   final int[] betArray = RedBlackTable.getConfig().getBetArray();
                //正常获取用户信息
                Type type0 = new TypeToken<JsonBean<UserLoginInfo>>() {
                }.getType();

                JsonBean<UserLoginInfo> bean = gson.fromJson(result, type0);
                UserLoginInfo userLoginInfo = bean.data;
                final int uid = login.getUid();

                //查询数据库,该用户游玩此游戏的次数。
                int playCounts = UserScoreDaoImpl.getInstance().getPlayCounts(GAME_ID, uid);
                UserInfo userInfo = new UserInfo();
                userInfo.setUid(uid);
                userInfo.setName(userLoginInfo.getUser_nickname());
                userInfo.setMac(login.getToken());//记录token,防止盗刷
                userInfo.setPlayCounts(playCounts);//记录游玩次数
                userInfo.setLuckyValue(Utils.random(1, 100));//随机幸运值
                userInfo.setScore(userLoginInfo.getScore());//记录玩家登录分数状态
                userInfo.setUserLoginInfo(userLoginInfo);//记录玩家登录分数状态
/*                Prize prize = new Prize();
                prize.loadDb(GAME_ID, uid, betArray);
                userInfo.setPrize(prize);*/
                String tableId = login.getViewingTableId();
                userMap.put(uid, userInfo);//大厅记录所有玩家的登录信息
                webMap.put(uid, conn);//大厅记录所有玩家的登录连接
//                if (tableId == null || tableId.equals("0")) {
//                    String log1 = ("获取分数" + result);
//                    LogWindows.getLogWindows().printToTextArea(log1, SocketServer.class);
//                    FileUtils.writeTxtToFile(log1, LogDate(), getFileName(uid));
//                    List<PostJson> emailList = UserScoreDaoImpl.getInstance().getEmailList(GAME_ID, userInfo.getUid());
//                    send(conn, GAME_MAIN, GAME_C_SUB_EMAIL_LIST_RETURN, emailList);
//
//                    send(conn, GAME_MAIN, GAME_C_SUB_ENTER_ROOM_RETURN, userLoginInfo);
//                    // send(conn, GAME_MAIN, GAME_SUB_GAME_PRIZE_LIST, prize);
//                }
                if (tableId != null && tableId.equals("1")) {
                    RedBlackMatch.getInstance().addMatchUser(conn, userInfo);
                } else {
                    send(conn, GAME_MAIN, GAME_C_SUB_ENTER_ROOM_RETURN, userLoginInfo);
                }
            }

        }).start();

    }

    private void sendGameConfig(WebSocket conn) {
        com.game.service.game.redblack.TableConfig config = new com.game.service.game.redblack.TableConfig();
        RedBlackConfig redBlackConfig = RedBlackTable.getConfig();
        config.setRedOdds(redBlackConfig.getRedOdds());
        config.setBlackOdds(redBlackConfig.getBlackOdds());
        config.setBetArray(redBlackConfig.getBetArray());
        config.setRoomRatio(redBlackConfig.getRoomRatio());
        send(conn, GAME_MAIN, GAME_SUB_GAME_CONFIG, config);
    }


    public void send(WebSocket conn, int main, int sub, Object cmd) {

        if (conn == null) {

            return;
        }
        Gson gson = new Gson();
        GameMessage gameMessage = new GameMessage();
        gameMessage.setMain(main);
        gameMessage.setSub(sub);
        gameMessage.setCmd(cmd);
        String json = gson.toJson(gameMessage);
        if (conn.getReadyState() == ReadyState.OPEN) {
            conn.send(json);
        }


        // System.out.println(conn.getReadyState()+","+main+"-"+sub);
    }


    private int runTime = 0;


    /**
     * 服务器开启成功后运行游戏线程
     */
    public void onGameRun() {
        CountdownTimer countdown = new CountdownTimer(); //
        TimerTask task = new TimerTask() {

            public void run() {

                try {
                    MyGameRun();
                } catch (Exception e) {
                    String error = "GameRun()" + e + "\n" + Arrays.toString(e.getStackTrace());
                    FileUtils.writeTxtToFile(error, LogDate(), LOG_NAME_ERROR);
                }

            }

            private void MyGameRun() {

                runTime++;
                SystemClose();
                if (runTime % 180 == 0) {
                    //处理未发送成功的订单
                    PostJsonDealFailed.getInstance().dealFailJson();
                    checker.cleanup();
                }
                if (runTime % 60 == 0) {
                    //定时发送在线用户
                    postOnlineUser();
                }

            }
        };
        countdown.startTimer(task);
    }

    private void SystemClose() {
        if (Client.isClose()) {
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    System.exit(1);
                }
            };
            Timer timer = new Timer();
            timer.schedule(task, 5000);
        }
    }


    public static String getFileName(int uid) {
        return uid + ".log";
    }


    public void sendErrorMsg(WebSocket conn, Object cmd) {
        send(conn, GAME_MAIN, GAME_SUB_SOCKET_ERROR, cmd);
    }

    /***
     *
     * @return  "game_GAME_ID_时间_";
     */
    private String orderIdHead() {
        tableIdIndex++;
        return "game_" + GAME_ID + "_" + Utils.getDateTableId() + "_";
    }

    public void initGameConfig(TurntableConfig gameConfig) {

    }


    /**
     * 获取总服务器配置信息,每局都去获取
     */
    private void initConfig() {
        FileUtils.writeTxtToFile("获取配置,请求地址:" + Score.API_GET_CONFIG, Utils.LogDate(), LOG_NAME_ROOM);
        new Thread(() -> {
            GetConfig config = new GetConfig();
            config.setGameid(GAME_ID);
            String json0 = new Gson().toJson(config);
            String result = doPostForm(API_GET_CONFIG, json0);

            if (result.isEmpty()) {
                LogWindows.getLogWindows().printToTextArea("获取配置:失败", SocketServer.class);
                return;
            }
            Type type0 = new TypeToken<JsonBean<TurntableConfig>>() {
            }.getType();

            JsonBean<TurntableConfig> bean = new Gson().fromJson(result, type0);

            String log = String.format("获取配置:%s", result + bean);
            LogWindows.getLogWindows().printToTextArea(log, SocketServer.class);
            if (bean.data != null) {
                FileUtils.writeTxtToFile("获取配置,获取成功:", Utils.LogDate(), LOG_NAME_ROOM);
                initGameConfig(bean.data);
            }

        }).start();
    }


    public void printTime(String name, long time) {
        String hs = (System.currentTimeMillis() - time) + "ms";
        String log = String.format("%s耗时:%s\n", name, hs);
        LogWindows.getLogWindows().printToTextArea(log, SocketServer.class);
    }


    private void Bet(WebSocket conn, String json) {
        long start = System.currentTimeMillis();
        //玩家押注
        Type type = new TypeToken<GameMessage<UserBet>>() {
        }.getType();//无敌好用
        GameMessage<UserBet> data = new Gson().fromJson(json, type);
        UserBet userBet = data.getCmd();
        String orderIdHead = orderIdHead();
        userBet.setOrderIdFee(orderIdHead + ORDER_FEE + tableIdIndex);
        userBet.setOrderIdPrize(orderIdHead + ORDER_PRIZE + tableIdIndex);
        LogWindows.getLogWindows().printToTextArea(userBet.toString(), SocketServer.class);
        if (userBet.getTableType() == 1) {
            RedBlackMatch.getInstance().betMatch(conn, userBet);
            return;
        }

//        //TODO  玩家参加游戏，提交参赛信息给游戏服务器。发送订单给总服务器,订单完成后。
//        new Thread(() -> {
//            //  String feeOrder = createFeeOrderJson(userBet);
//            //加密发送
//            String plainText = createFeeOrderJson(userBet);
//            EncipheredData eventJson = AESUtils.createEncipheredData(plainText);
//            String feeOrder = new Gson().toJson(eventJson);
//            String result = doPostForm(API_POST_FEE_ORDER, feeOrder);
//
//            if (result.isEmpty()) {
//                send(conn, GAME_MAIN, GAME_C_SUB_BET_RETURN, null);//提交门票订单,失败
//                LogWindows.getLogWindows().printToTextArea("提交参赛订单失败", SocketServer.class);
//                return;
//            }
//            Type type0 = new TypeToken<JsonBean<FeeOrderReturn>>() {
//            }.getType();
//
//            JsonBean<FeeOrderReturn> bean = new Gson().fromJson(result, type0);
//
//            //TODO 门票订单成功
//            // 1.总服务器返回给最新的分数信息,
//            // 2.给客户端开奖信息,
//            // 3.同时提交游戏结果给总服务器。
//            if (bean.code == 0 && bean.data != null) {
//                feeOrderSuccess(conn, userBet, bean.data);
//                printTime(userBet.getOrderIdFee() + "门票订单成功", start);
//            } else {
//                send(conn, GAME_MAIN, GAME_C_SUB_BET_RETURN, null);//提交门票订单,失败
//                sendErrorMsg(conn, bean);
//            }
//
//
//        }).start();


    }

    public void feeOrderSuccess(WebSocket conn, UserBet userBet, FeeOrderReturn feeOrderReturn) {
        UserInfo userInfo = getUser(userBet.getUid(), userBet.getToken());
        final String orderid = userBet.getOrderIdPrize();
        //TODO 2025-07-02 更新难度控制
        if (userInfo == null) {
            return;
        }
        GameResult gameResult = RedBlackTable.onTurntableGameResult(orderid, feeOrderReturn, userBet, userInfo);
        final String json = new Gson().toJson(gameResult);
        gameResult.itemStatus = 0;
        executor.submit(() -> {
            long start = System.currentTimeMillis();
            GameResult gameResultCopy = new Gson().fromJson(json, GameResult.class);
            if (userInfo != null && userInfo.getPrize() != null) {
                userInfo.getPrize().write();//写入数据库
            }
            PostJsonDeal postJsonDeal = new PostJsonDeal();
            String postJson = createPlayingJson(userBet, gameResultCopy);
            //TODO 游戏结算订单
            postJsonDeal.post(postJson, API_POST_PRIZE_ORDER, PostJsonDeal.POST_TYPE_PLAYING, userBet.getOrderIdPrize(), userBet.getUid());
            FileUtils.writeTxtToFile(writeLog(postJson, PostJsonDeal.POST_TYPE_PLAYING), LogDate(), getFileName(userBet.getUid()));
            printTime(userBet.getOrderIdPrize() + "游戏订单写入", start);
        });
        send(conn, GAME_MAIN, GAME_C_SUB_BET_RETURN, gameResult);
        send(conn, GAME_MAIN, GAME_SUB_GAME_PRIZE_LIST, userInfo.getPrize());
    }

    /***创建门票订单
     *
     * @param userBet 用户投注
     * @return 门票订单
     */

    public String createFeeOrderJson(UserBet userBet) {
        final String orderid = userBet.getOrderIdFee();
        OrderModel model = new OrderModel();
        model.setOrderid(orderid);
        TableFeeInfo info = new TableFeeInfo();
        info.setUid(userBet.getUid());
        info.setToken(userBet.getToken());
        info.setLiveid(userBet.getLiveid());
        info.setStream(userBet.getStream());

        info.setGameid(GAME_ID);//游戏id
        info.setFee(RedBlackTable.getBetNumber(userBet.getBet()));//实际的押注数量
        info.setTableType(userBet.getTableType());

        model.setTableInfo(info);
        model.setAddtime(System.currentTimeMillis());

        String json = new Gson().toJson(model);
        String sign = Utils.encryptMD5(json);
        model.setSign(sign);
        String feeOrderJson = new Gson().toJson(model);
        LogWindows.getLogWindows().printToTextArea(feeOrderJson, SocketServer.class);
        return feeOrderJson;

    }

    /***创建订单-正常游玩
     *
     * @param userBet 下注信息
     * @param gameResult 游戏结果
     * @return 结算订单json
     */
    public String createPlayingJson(UserBet userBet, GameResult gameResult) {
        PlayingModel model = new PlayingModel();
        model.setOrderid(gameResult.orderid);
        PlayingInfo info = new PlayingInfo();
        info.setUid(userBet.getUid());
        info.setToken(userBet.getToken());
        info.setLiveid(userBet.getLiveid());
        info.setStream(userBet.getStream());
        info.setOs(userBet.getOs());
        info.setTableType(userBet.getTableType());
        //中奖的内容
        info.setGameid(GAME_ID);
        info.setFee(gameResult.fee);
        info.setPrize(gameResult.prize);
        info.setItem(gameResult.item);
        info.setRatio(gameResult.ratio);
        info.setDeduction(gameResult.deduction);
        info.setRemarks(gameResult);
        model.setResult(info);
        model.setAddtime(System.currentTimeMillis());

        String json = new Gson().toJson(model);
        String sign = Utils.encryptMD5(json);
        model.setSign(sign);
        String gameResultJson = new Gson().toJson(model);
        LogWindows.getLogWindows().printToTextArea(gameResultJson, SocketServer.class);
        return gameResultJson;

    }


    /*** 创建订单-每日活动
     *
     * @param userExchangePrizeDaily 兑奖信息
     * @param prizeDaily 兑换结果
     * @return 兑换订单json
     */
    public String createExchangePrizeDailyJson(UserExchangePrizeDaily userExchangePrizeDaily, PrizeDaily prizeDaily) {
        PlayingModel model = new PlayingModel();
        model.setOrderid(userExchangePrizeDaily.getOrderIdPrize());
        PlayingInfo info = new PlayingInfo();
        info.setUid(userExchangePrizeDaily.getUid());
        info.setToken(userExchangePrizeDaily.getToken());
        info.setLiveid(userExchangePrizeDaily.getLiveid());
        info.setStream(userExchangePrizeDaily.getStream());
        info.setOs(userExchangePrizeDaily.getOs());
        info.setTableType(userExchangePrizeDaily.getTableType());

        //中奖的内容
        info.setGameid(GAME_ID);
        info.setFee(0);//活动-免费领取
        info.setPrize(prizeDaily.getPrizeDiamondSend());
        info.setItem(0xFFFF);//每日活动-中奖代号
        info.setRatio("UserExchangePrizeLuckyValue");//备注
        info.setRemarks(prizeDaily);
        model.setResult(info);
        model.setAddtime(System.currentTimeMillis());

        String json = new Gson().toJson(model);
        String sign = Utils.encryptMD5(json);
        model.setSign(sign);
        String gameResultJson = new Gson().toJson(model);
        LogWindows.getLogWindows().printToTextArea(gameResultJson, SocketServer.class);
        return gameResultJson;

    }

    /*** 创建订单-兑换幸运积分
     *
     * @param user 用户兑奖信息
     * @param prize 兑换结果
     * @return 兑换订单json
     */
    public String createExchangePrizeLuckyValueJson(UserExchangePrizeLuckyValue user, PrizeLucky prize) {
        PlayingModel model = new PlayingModel();
        model.setOrderid(user.getOrderIdPrize());
        PlayingInfo info = new PlayingInfo();
        info.setUid(user.getUid());
        info.setToken(user.getToken());
        info.setLiveid(user.getLiveid());
        info.setStream(user.getStream());
        info.setOs(user.getOs());
        info.setTableType(user.getTableType());
        //中奖的内容
        info.setGameid(GAME_ID);
        info.setFee(0);//活动-免费领取
        info.setPrize(prize.getPrizeDiamondSend());
        info.setItem(0xFFFE);//积分兑换-中奖代号
        info.setRatio("UserExchangePrizeLuckyValue");//备注
        info.setRemarks(prize);//备注
        model.setResult(info);
        model.setAddtime(System.currentTimeMillis());

        String json = new Gson().toJson(model);
        String sign = Utils.encryptMD5(json);
        model.setSign(sign);
        String gameResultJson = new Gson().toJson(model);
        LogWindows.getLogWindows().printToTextArea(gameResultJson, SocketServer.class);
        return gameResultJson;

    }

    private UserInfo getUser(int uid, String token) {
        UserInfo userInfo = userMap.get(uid);
        if (userInfo != null && userInfo.getMac().equals(token)) {
            return userInfo;
        }
        return null;
    }

    private String writeLog(String content, String desc) {
        return desc + "-" + content;

    }

    public void printSystemRunInfo() {
        long start = System.currentTimeMillis();
        executor.submit(() -> {
            new PrintGameRunInfo().getGameRunInfo();
            printTime("获取系统收益情况", start);
        });
    }

    /*** 获取邮件List ,保留一个月
     *
     * @param conn
     * @param json
     */
    private void getEmailList(WebSocket conn, String json) {
        //获取自己全部的邮件
        Type type = new TypeToken<GameMessage<UserEmail>>() {
        }.getType();//无敌好用
        GameMessage<UserEmail> data = new Gson().fromJson(json, type);
        UserEmail userEmail = data.getCmd();

        if (userEmail == null) {
            return;
        }
        UserInfo userInfo = getUser(userEmail.getUid(), userEmail.getToken());
        if (userInfo == null) {//校验玩家token,信息错误则忽略请求
            return;
        }
        new Thread(() -> {
            List<PostJson> emailList = UserScoreDaoImpl.getInstance().getEmailList(GAME_ID, userInfo.getUid());
            send(conn, GAME_MAIN, GAME_C_SUB_EMAIL_LIST_RETURN, emailList);
            String log = String.format("用户%s,获取邮件%s", userInfo.getUid(), emailList.size());
            LogWindows.getLogWindows().printToTextArea(log, SocketServer.class);
        }).start();
    }

    /*** 领取邮件奖励
     *
     * @param conn
     * @param json
     */

    private void emailClaimPrize(WebSocket conn, String json) {
        Type type = new TypeToken<GameMessage<UserEmail>>() {
        }.getType();//无敌好用
        GameMessage<UserEmail> data = new Gson().fromJson(json, type);
        UserEmail userEmail = data.getCmd();

        if (userEmail == null) {
            return;
        }
        UserInfo userInfo = getUser(userEmail.getUid(), userEmail.getToken());
        if (userInfo == null) {//校验玩家token,信息错误则忽略请求
            return;
        }
        new Thread(() -> {
            EmailDeal emailDeal = new EmailDeal();
            emailDeal.addListener(new EmailDeal.ISendListener() {
                @Override
                public void sendSuccess() {
                    send(conn, GAME_MAIN, GAME_C_SUB_EMAIL_CLAIM_PRIZE_RETURN, null);
                }

                @Override
                public void error(String e) {

                }
            });
            emailDeal.dealEmail(userEmail.getUid(), userEmail.getOrderIdEmail());
        }).start();

    }

    /*** 删除邮件
     *
     * @param conn
     * @param json
     */
    private void emailDelete(WebSocket conn, String json) {
        Type type = new TypeToken<GameMessage<UserEmail>>() {
        }.getType();//无敌好用
        GameMessage<UserEmail> data = new Gson().fromJson(json, type);
        UserEmail userEmail = data.getCmd();

        if (userEmail == null) {
            return;
        }
        UserInfo userInfo = getUser(userEmail.getUid(), userEmail.getToken());
        if (userInfo == null) {//校验玩家token,信息错误则忽略请求
            return;
        }
        new Thread(() -> {
            EmailDeal emailDeal = new EmailDeal();
            emailDeal.addListener(new EmailDeal.ISendListener() {
                @Override
                public void sendSuccess() {
                    send(conn, GAME_MAIN, GAME_C_SUB_EMAIL_DELETE_RETURN, null);
                }

                @Override
                public void error(String e) {

                }
            });
            emailDeal.deleteEmail(userEmail.getUid(), userEmail.getOrderIdEmail());
        }).start();

    }

    /**
     * 实时更新自研游戏在线用户
     *
     * @apiNote
     */

    private void postOnlineUser() {

        new Thread(() -> {
            OnlineUser onlineUser = new OnlineUser();
            onlineUser.setGameid(GAME_ID);
            onlineUser.setTotal(userMap.size());
            List<Integer> data = new ArrayList<>();
            userMap.forEach((key, value) -> {
                data.add(key);
            });
            onlineUser.setData(data);
            String plainText = new Gson().toJson(onlineUser);
            EncipheredData eventJson = AESUtils.createEncipheredData(plainText);
            String json = new Gson().toJson(eventJson);
            String result = doPostForm(API_POST_ONLINE_USER_REPORT, json);
            String log = "提交游戏在线用户:" + result;
            LogWindows.getLogWindows().printToTextArea(log, SocketServer.class);
        }).start();
    }

}